package com.xzzz.irda.guardcat.server.alert;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import com.xzzz.common.base.enums.YesNo;
import com.xzzz.common.base.pojo.PageRes;
import com.xzzz.common.base.util.BeanUtil;
import com.xzzz.common.base.util.DateUtils;
import com.xzzz.common.dblog.pojo.LogEntity;
import com.xzzz.irda.guardcat.core.pojo.Alert;
import com.xzzz.irda.guardcat.server.repos.mysql.mappers.AlertMapper;
import com.xzzz.irda.guardcat.server.repos.mysql.pojo.AlertMySQLEntity;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.*;
import java.util.stream.Collectors;

@Slf4j
public class AlertManagerInMySQL extends AbstractAlertManager {

    @Autowired
    private AlertMapper alertMapper;

    @Override
    public PageRes<Alert> pages(String appName, String machineId, String id, Boolean read, Integer pageSize, Integer pageNum) {
        Page<LogEntity> page = PageHelper.startPage(pageNum, pageSize);

        QueryWrapper<AlertMySQLEntity> where = new QueryWrapper<>();
        if (StrUtil.isNotBlank(appName)) {
            where.eq("app_name", appName);
        }
        if (StrUtil.isNotBlank(id)) {
            where.eq("id", id);
        }
        if (read != null && read) {
            where.notLike("read_status", YesNo.YES.getValue());
        }
        where.orderByDesc("cre_time");

        List<AlertMySQLEntity> entityList = alertMapper.selectList(where);
        List<Alert> result = new ArrayList<>();
        for (AlertMySQLEntity entity : entityList) {
            Alert alert = entityTo(entity);
            result.add(alert);
        }

        PageRes<Alert> pageRes = new PageRes<>(result);
        pageRes.setTotal(page.getTotal());
        pageRes.setPageNum(pageNum);
        pageRes.setPageSize(pageSize);
        return pageRes;
    }

    @Override
    public Map<String, Object[]> histogram(String appName, String machineId) {
        Date now = DateUtils.date();
        String startTime = DateUtils.toYMDHMS(DateUtils.offsetHour(now, -48));
        Date nowHour = DateUtils.parse(DateUtils.format(now, "yyyy-MM-dd HH") + ":00:00");
        Map<String, Integer> hour48 = new TreeMap<>();
        for (int i = 0; i < 48; i++) {
            hour48.put(DateUtils.toYMDHMS(nowHour), 0);
            nowHour = DateUtils.offsetHour(nowHour, -1);
        }

        QueryWrapper<AlertMySQLEntity> where = new QueryWrapper<>();
        if (StrUtil.isNotBlank(appName)) {
            where.eq("app_name", appName);
        }
        where.gt("cre_time", startTime)
            .orderByDesc("cre_time");

        List<AlertMySQLEntity> entityList = alertMapper.selectList(where);

        Map<String, Object[]> result = new HashMap<>();
        List<String> dates = new ArrayList<>();
        List<Integer> counts = new ArrayList<>();
        long interval = 1000 * 60 * 60;
        for (AlertMySQLEntity alert : entityList) {
            long gmtTs = alert.getCreTime().getTime() - alert.getCreTime().getTime() % interval;
            String creTime = DateUtils.toYMDHMS(DateUtils.date(gmtTs));
            int i = hour48.getOrDefault(creTime,0);
            hour48.put(creTime, ++i);
        }
        hour48.forEach((k, v) -> {
            dates.add(k);
            counts.add(v);
        });

        result.put("dates", dates.toArray());
        result.put("counts", counts.toArray());
        return result;
    }

    @Override
    public void add(Alert alert) {
        AlertMySQLEntity entity = toEntity(alert);
        alertMapper.insert(entity);
    }

    @Override
    public void read(String alertId) {
        AlertMySQLEntity entity = new AlertMySQLEntity();
        entity.setId(alertId);
        entity.setReadStatus(YesNo.YES.getValue());
        alertMapper.updateById(entity);
    }

    @Override
    public void expire() {

    }

    @Override
    public long countMachine(String machineId, Boolean read) {
        QueryWrapper<AlertMySQLEntity> where = new QueryWrapper<>();
        if (StrUtil.isNotBlank(machineId)) {
            where.eq("machine_id", machineId);
        }
        if (read != null && read) {
            where.notLike("read_status", YesNo.YES.getValue());
        }
        return alertMapper.selectCount(where);
    }

    @Override
    public Map<String, Long> countMachine(Collection<String> machineIds, Boolean read) {
        QueryWrapper<AlertMySQLEntity> where = new QueryWrapper<>();
        if (CollUtil.isNotEmpty(machineIds)) {
            where.in("machine_id", machineIds);
        }
        if (read != null && read) {
            where.notLike("read_status", YesNo.YES.getValue());
        }
        List<AlertMySQLEntity> alerts = alertMapper.selectList(where);
        Map<String, List<AlertMySQLEntity>> countMaps = alerts.stream().collect(Collectors.groupingBy(AlertMySQLEntity::getMachineId));
        Map<String, Long> counts = new HashMap<>();
        for (String machineId : machineIds) {
            List<AlertMySQLEntity> alertList = countMaps.get(machineId);
            counts.put(machineId, (long) (CollUtil.isEmpty(alertList) ? 0 : alertList.size()));
        }
        return counts;
    }

    @Override
    public long countApp(String appName, Boolean read) {
        QueryWrapper<AlertMySQLEntity> where = new QueryWrapper<>();
        if (StrUtil.isNotBlank(appName)) {
            where.eq("app_name", appName);
        }
        if (read != null && read) {
            where.notLike("read_status", YesNo.YES.getValue());
        }
        return alertMapper.selectCount(where);
    }

    private static Alert entityTo(AlertMySQLEntity entity) {
        Alert alert = BeanUtil.toObj(entity, Alert.class);
        alert.setNotification(YesNo.is(entity.getNotification()));
        alert.setRead(YesNo.is(entity.getReadStatus()));
        alert.setLevel(Alert.Level.getByName(entity.getAlertLevel()));
        return alert;
    }

    private static AlertMySQLEntity toEntity(Alert alert) {
        AlertMySQLEntity entity = BeanUtil.toObj(alert, AlertMySQLEntity.class);
        entity.setNotification(YesNo.toInt(alert.getNotification()));
        entity.setReadStatus(YesNo.toInt(alert.getRead()));
        entity.setAlertLevel(alert.getLevel().name());
        return entity;
    }
}
